#ifndef __STREAM_WRITER__
#define __STREAM_WRITER__

#include "stream_reader.h"

class StreamWriter
{
public:
	StreamWriter() : dataStream_(*new DataStream), stream_(dataStream_.stream_) {
		dataStream_.retain();
	}

	StreamWriter(DataStream* stream) : dataStream_(*stream), stream_(dataStream_.stream_) {
		dataStream_.retain();
	}

	StreamWriter(const StreamWriter&) = delete;

	virtual ~StreamWriter() { dataStream_.release(); }

	void operator=(StreamWriter&) = delete;

	inline int32 length() {
		return static_cast<int32>(stream_.size());
	}

	inline uint8* data() {
		return stream_.data();
	}

	inline DataStream* dataStream() {
		return &dataStream_;
	}

	inline StreamReader createStreamReader() {
		return StreamReader(dataStream_);
	}

	inline StreamWriter& operator << (bool v) {
		return writeNumber((uint8)v);
	}

	inline StreamWriter& operator << (int8 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (uint8 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (int16 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (uint16 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (int32 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (uint32 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (int64 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (uint64 v) {
		return writeNumber(v);
	}

	inline StreamWriter& operator << (const Guid64& v) {
		return writeNumber(v.getValue());
	}

	inline StreamWriter& operator << (float32 v) {
		return writeNumber(static_cast<int32>(v * 100));
	}

	inline StreamWriter& operator << (float64 v) {
		return writeNumber(static_cast<int64>(v * 100));
	}

	inline StreamWriter& operator << (const std::string& str) {
		writeNumber((int32)str.size());
		stream_.resize(stream_.size() + str.size());
		memcpy(stream_.data() + stream_.size() - str.size(), str.data(), str.size());
		writeNumber((uint8)'\0');
		return *this;
	}

	inline StreamWriter& operator << (const char* str) {
		shengine_assert(str);
		str = str ? str : "";
		int32 strLen = (int32)strlen(str);
		writeNumber(strLen);
		stream_.resize(stream_.size() + strLen);
		memcpy(stream_.data() + stream_.size() - strLen, str, strLen);
		writeNumber((uint8)'\0');
		return *this;
	}

	inline StreamWriter& operator << (void* udata) {
		writeNumber((uint64)udata);
		return *this;
	}

	inline StreamWriter& writeBuffer(const uint8* data, int32 sz) {
		shengine_assert(data);
		if (data) {
			writeNumber((int32)sz);
			stream_.resize(stream_.size() + sz);
			memcpy(stream_.data() + stream_.size() - sz, data, sz);
		}
		return *this;
	}

	inline StreamWriter& appenBuffer(const uint8* data, int32 sz) {
		shengine_assert(data);
		if (data) {
			stream_.resize(stream_.size() + sz);
			memcpy(stream_.data() + stream_.size() - sz, data, sz);
		}
		return *this;
	}

private:
	template<typename _Ty>
	inline StreamWriter& writeNumber(_Ty v) {
		stream_.resize(stream_.size() + sizeof(v));
		*(_Ty*)(stream_.data() + stream_.size() - sizeof(v)) = v;
		return *this;
	}

protected:
	DataStream& dataStream_;
	std::vector<uint8>& stream_;
};

#endif
